07. Use the Fake Repository inside a ViewModel
L5 P3 A03 Use The Fake Repository Inside A ViewModel V2
In this task you'll use a fake class inside of a ViewModel. This will involve the use of a ViewModelProvider.Factory; this was explained in the Developing Android Apps with Kotlin Course's Lesson 5: App Architecture (UI Layer) - Concept 22. Exercise: Add a ViewModelFactory.
Step 1: Make and use a ViewModelFactory in TasksViewModel
You'll start with just updating the classes and test related to the Tasks screen.
- Open
TasksViewModel. - Change the constructor of
TasksViewModelto take inTasksRepositoryrather than constructing it inside the class:
TasksViewModel.kt
// REPLACE
class TasksViewModel(application: Application) : AndroidViewModel(application) {
private val tasksRepository = DefaultTasksRepository.getRepository(application)
// Rest of class
}
// WITH
class TasksViewModel( private val tasksRepository: TasksRepository ) : ViewModel() {
// Rest of class
}
Since you changed the constructor, you now need to use a ViewModelProvider.Factory to construct TasksViewModel. You'll put the factory class in the same file as the TasksViewModel, but you could also put it in its own file.
- At the bottom of the
TasksViewModelfile, outside the class, add aTasksViewModelFactorywhich takes in a plainTasksRepository:
TasksViewModel.kt
@Suppress("UNCHECKED_CAST")
class TasksViewModelFactory (
private val tasksRepository: TasksRepository
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>) =
(TasksViewModel(tasksRepository) as T)
}
Now that you have the factory, use it wherever you construct your view model.
- Update
TasksFragmentto use the factory:
TasksFragment.kt
// REPLACE
private val viewModel by viewModels<TasksViewModel>()
// WITH
private val viewModel by viewModels<TasksViewModel> {
TasksViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
}
- Run your app code and make sure everything is still working!
Step 2: Use FakeTestRepository inside TasksViewModelTest
Now instead of using the real repository in your view model tests, you can use the fake repository.
- Open up
TasksViewModelTest. - Add a
FakeTestRepositoryproperty in theTasksViewModelTest:
TasksViewModelTest.kt TKTK check
@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
// Use a fake repository to be injected into the viewmodel
private lateinit var tasksRepository: FakeTestRepository
// Rest of class
}
- Update the
setupViewModelmethod to make aFakeTestRepositorywith three tasks and then construct thetasksViewModelwith this repository.
TasksViewModelTest.kt
@Before
fun setupViewModel() {
// We initialise the tasks to 3, with one active and two completed
tasksRepository = FakeTestRepository()
val task1 = Task("Title1", "Description1")
val task2 = Task("Title2", "Description2", true)
val task3 = Task("Title3", "Description3", true)
tasksRepository.addTasks(task1, task2, task3)
tasksViewModel = TasksViewModel(tasksRepository)
}
- Because you are no longer using the AndroidX Test
ApplicationProvider.getApplicationContextcode, you can also remove the@RunWith(AndroidJUnit4::class)annotation. - Run your tests, make sure they all still work!
By using constructor dependency injection, you've now removed the DefaultTasksRepository as a dependency and replaced it with your FakeTestRepository in the tests.
Step 3. Also Update TaskDetail Fragment and ViewModel
Following the same sets you just completed, on your own, do the same steps for TaskDetailFragment and TaskDetailViewModel:
- Update the
TaskDetailViewModelconstructor to take in aTasksRepository. - Add a
TaskDetailViewModelFactory. - Update the
TaskDetailFragmentto use the factory.
Remember to run your application code! The app should work exactly the same, even though you refactored the code.
If you'd like to avoid building a separate factory for each view model, check out the Architecture Blueprints reactive sample, which shows a slightly more complicated version of the tests you are building. It includes a generic ViewModelFactory that can generate any view model needed and this extension function.
You are now able to use a FakeTestRepository instead of the real repository in TasksFragment and TasksDetailFragment.